home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-01 | 36.3 KB | 1,472 lines |
- /*0*********************************************************
- * Richard Carver July 1990
- *
- * This program demonstrates interprocess communication
- * between several tasks using the iRMX II Operating
- * System.
- *
- * Two tasks are used for resource control. The
- * clock_task() controls use of the hardware clock and the
- * crt_task() controls use of the display screen.
- *
- * The count_task() competes with the clock_task() for
- * use of the crt_task() services. The timer_task() uses
- * the services of the clock_task() for a software timer.
- *
- * The initial task, main(), starts every thing up and,
- * when the timer_task() finishes, shuts everything down.
- ***********************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <rmxc.h> /* iRMX OS calls & structures */
- #include <rmxerr.h> /* iRMX status codes (defines) */
- #include <delay.h> /* Hardcoded delay loop macros */
-
- #define ERROR (0xFFFF) /* Error Condition */
-
- #define FALSE (0)
- #define TRUE (!FALSE)
-
- #define MAX_CLOCK_RETRIES (4)
-
- /* The NULL token (similar to NULL pointer) */
-
- #define NUL_TKN ((selector)0)
-
- /* Options for rqgettasktokens() */
-
- #define THIS_TASK (0x00)
- #define THIS_JOB (0x01)
- #define PARAM_OBJ (0x02)
- #define ROOT_JOB (0x03)
-
- /* Options for rqcreatemailbox() */
-
- #define FIFO_OBJ_MBX (0x0000)
- #define PRIORITY_OBJ_MBX (0x0001)
- #define FIFO_DATA_MBX (0x0020)
- #define PRIORITY_DATA_MBX (0x0021)
-
- /* Options for rqcreatesemaphore() */
-
- #define FIFO_SEM (0x0000)
- #define PRIORITY_SEM (0x0001)
-
- #define SEM_INIT_0 (0)
- #define SEM_MAX_1 (1)
-
- /* Common wait times for iRMX System Calls */
-
- #define NO_WAIT (0x0000)
- #define WAIT_FOREVER (0xFFFF)
-
- /* Options for rqcreatetask() */
-
- #define NO_FLOAT (0x0000)
- #define DEFAULT_STACK_SIZE ((unsigned int)2048)
-
- /* Task Priorities */
-
- #define CLOCK_TASK_PRIORITY ((unsigned char)48)
- #define TIMER_TASK_PRIORITY ((unsigned char)150)
- #define CRT_TASK_PRIORITY ((unsigned char)200)
- #define COUNT_TASK_PRIORITY ((unsigned char)200)
-
- /* Defines For Hardware Clock */
- /* Clock Interrupt Level */
-
- #define CLOCK_INT_LEVEL (0x26)
-
- /* Clock Ports */
-
- #define ADR_PORT ((unsigned short)0xA060)
- #define DAT_PORT ((unsigned short)0xA062)
- #define CNT_PORT ((unsigned short)0xA064)
- #define PIO_PORT ((unsigned short)0xA066)
-
- /* Clock Port I/O Operations */
-
- #define PIO_READ ((unsigned char)0x82)
- #define PIO_WRITE ((unsigned char)0x80)
-
- /* Clock Registers */
-
- #define SEC01_REG (0x00)
- #define SEC10_REG (0x01)
- #define MIN01_REG (0x02)
- #define MIN10_REG (0x03)
- #define HRS01_REG (0x04)
- #define HRS10_REG (0x05)
- #define DAT01_REG (0x07)
- #define DAT10_REG (0x08)
- #define MON01_REG (0x09)
- #define MON10_REG (0x0A)
- #define YRS01_REG (0x0B)
- #define YRS10_REG (0x0C)
-
- /* Clock Control Lines */
-
- #define CNT_RST ((unsigned char)0x00)
- #define INT_ENB ((unsigned char)0x20)
- #define HOLD_HIGH ((unsigned char)0x10)
- #define HOLD_READ ((unsigned char)0x30)
- #define HOLD_WRITE ((unsigned char)0x50)
-
- /* Defines for months */
-
- #define JANUARY (1)
- #define FEBRUARY (2)
- #define MARCH (3)
- #define DECEMBER (12)
-
- /* Time/Date and Timers Data Structure */
-
- #define MAX_TIMERS (10)
-
- struct SYS_TIME_STR
- {
- unsigned char change_flg;
- unsigned char second;
- unsigned char minute;
- unsigned char hour;
- unsigned char date;
- unsigned char month;
- unsigned char year;
-
- struct TIMER_STR
- {
- unsigned char in_use;
- unsigned int count;
- unsigned int timeout;
- selector sem_tkn;
- }timer[MAX_TIMERS];
- };
-
- /* Request Message format for the Display Task */
-
- struct CRT_REQ_STR
- {
- unsigned char *msg_ptr;
- unsigned int row;
- unsigned int col;
- };
-
- /* Object Catalog Names */
-
- const unsigned char
- clock_sem_name[] = "\011CLOCK_SEM",
- init_sem_name[] = "\010INIT_SEM";
-
- const unsigned char
- time_seg_name[] = "\010TIME_SEG";
-
- const unsigned char
- crt_req_mbx_name[] = "\007CRT_MBX";
-
- const unsigned char
- crt_shtdwn_sem_name[] = "\012CRT_SHTDWN",
- clock_shtdwn_sem_name[] = "\014CLOCK_SHTDWN",
- count_shtdwn_sem_name[] = "\014COUNT_SHTDWN";
-
- /* Days Per Month */
-
- const unsigned char
- days_in_month[12] =
- {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
- /* Global System Time/Date Structure */
-
- selector sys_time_seg;
- struct SYS_TIME_STR *sys_time;
-
- /* Task declarations */
-
- void clock_task(void);
- void crt_task(void);
- void timer_task(void);
- void count_task(void);
-
- /* Task objects (global for debugging purposes) */
-
- selector clock_tsk;
- selector crt_tsk;
- selector timer_tsk;
- selector count_tsk;
-
- /*1*********************************************************
- * Task: main() (the initial task)
- *
- * Summary: Starts it all up and shuts it all down.
- *
- * Caveats: None
- ***********************************************************/
-
- void main(void)
- {
- selector current_job; /* current job */
- selector init_sem; /* initilaization sem */
- selector clock_sem; /* time/date shared memory*/
- selector clock_shtdwn_sem; /* clock_task() shutdown */
- selector count_shtdwn_sem; /* count_task() shutdown */
- selector crt_shtdwn_sem; /* crt_task() shutdown */
- selector sys_time_seg; /* time/date data segment */
-
- unsigned int status; /* iRMX condition code */
-
- struct EXCEPTIONSTRUCT exceptioninfo;
-
-
- /* Disable current task's exception handler */
-
- rqgetexceptionhandler(&exceptioninfo, &status);
- exceptioninfo.exceptionmode = 0;
- rqsetexceptionhandler(&exceptioninfo, &status);
-
- /* Get Token For Current Job */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- /* Create and catalog the semaphore used for */
- /* accessing the shared clock data. */
-
- clock_sem = rqcreatesemaphore(SEM_INIT_0,
- SEM_MAX_1, PRIORITY_SEM, &status);
- rqcatalogobject(current_job,
- clock_sem, &clock_sem_name, &status);
-
- /* Create and catalog the semaphore used for */
- /* synchronizing tasks during initialization */
- /* and shutdown. */
-
- init_sem = rqcreatesemaphore(SEM_INIT_0,
- 99, FIFO_SEM, &status);
- rqcatalogobject(current_job,
- init_sem, &init_sem_name, &status);
-
- /* Create and catalog the segment of memory */
- /* used to hold the shared time/date data. */
-
- sys_time_seg = rqcreatesegment(
- sizeof(struct SYS_TIME_STR), &status);
- rqcatalogobject(current_job,
- sys_time_seg, &time_seg_name, &status);
-
- /* Create and catalog the semaphores used to */
- /* signal task shutdown. */
-
- clock_shtdwn_sem = rqcreatesemaphore(SEM_INIT_0,
- SEM_MAX_1, FIFO_SEM, &status);
- rqcatalogobject(current_job,
- clock_shtdwn_sem, &clock_shtdwn_sem_name, &status);
-
- crt_shtdwn_sem = rqcreatesemaphore(SEM_INIT_0,
- SEM_MAX_1, FIFO_SEM, &status);
- rqcatalogobject(current_job,
- crt_shtdwn_sem, &crt_shtdwn_sem_name, &status);
-
- count_shtdwn_sem = rqcreatesemaphore(SEM_INIT_0,
- SEM_MAX_1, FIFO_SEM, &status);
- rqcatalogobject(current_job,
- count_shtdwn_sem, &count_shtdwn_sem_name, &status);
-
- /* Create the crt_task(). Wait for the task to */
- /* indicate it has completed initialization. */
-
- crt_tsk = rqcreatetask(CRT_TASK_PRIORITY, &crt_task,
- NUL_TKN, NULL, DEFAULT_STACK_SIZE, NO_FLOAT, &status);
-
- rqreceiveunits(init_sem, 1, WAIT_FOREVER, &status);
-
- /* Create the clock_task(). Wait for the task */
- /* to indicate it has completed initialization. */
-
- clock_tsk = rqcreatetask(CLOCK_TASK_PRIORITY, &clock_task,
- NUL_TKN, NULL, DEFAULT_STACK_SIZE, NO_FLOAT, &status);
-
- rqreceiveunits(init_sem, 1, WAIT_FOREVER, &status);
-
- /* Create the count_task(). Wait for the task */
- /* to indicate it has completed initialization. */
-
- count_tsk = rqcreatetask(COUNT_TASK_PRIORITY, &count_task,
- NUL_TKN, NULL, DEFAULT_STACK_SIZE, NO_FLOAT, &status);
-
- rqreceiveunits(init_sem, 1, WAIT_FOREVER, &status);
-
- /* Create the timer_task(). Wait for the task */
- /* to indicate it has completed initialization. */
- /* This also signals the shutdown process. */
-
- timer_tsk = rqcreatetask(TIMER_TASK_PRIORITY, &timer_task,
- NUL_TKN, NULL, DEFAULT_STACK_SIZE, NO_FLOAT, &status);
-
- rqreceiveunits(init_sem, 1, WAIT_FOREVER, &status);
-
- /* Begin shutdown by first disabling any further */
- /* interrupts from the hardware clock. This task */
- /* suspends itself for 2/100th of a second to */
- /* ensure interrupt is disabled. */
-
- rqdisable(CLOCK_INT_LEVEL, &status);
- rqsleep(2, &status);
-
- /* Send shutdown signals to all tasks and wait */
- /* for all tasks to complete shutdown. */
-
- rqsendunits(count_shtdwn_sem, 1, &status);
- rqsendunits(crt_shtdwn_sem, 1, &status);
- rqsendunits(clock_shtdwn_sem, 1, &status);
-
- rqreceiveunits(init_sem, 3, WAIT_FOREVER, &status);
-
- /* Cleanup before terminating. This includes */
- /* deleting tasks and uncataloging/deleteing */
- /* all objects created. */
-
- rqdeletetask(crt_tsk, &status);
- rqdeletetask(clock_tsk, &status);
- rqdeletetask(count_tsk, &status);
- rqdeletetask(timer_tsk, &status);
-
- rquncatalogobject(current_job,
- &clock_sem_name, &status);
- rquncatalogobject(current_job,
- &init_sem_name, &status);
- rquncatalogobject(current_job,
- &time_seg_name, &status);
- rquncatalogobject(current_job,
- &crt_req_mbx_name, &status);
-
- rquncatalogobject(current_job,
- &clock_shtdwn_sem_name, &status);
- rquncatalogobject(current_job,
- &count_shtdwn_sem_name, &status);
- rquncatalogobject(current_job,
- &crt_shtdwn_sem_name, &status);
-
- rqdeletesemaphore(clock_sem, &status);
- rqdeletesemaphore(init_sem, &status);
-
- rqdeletesemaphore(clock_shtdwn_sem, &status);
- rqdeletesemaphore(count_shtdwn_sem, &status);
- rqdeletesemaphore(crt_shtdwn_sem, &status);
-
- rqdeletesegment(sys_time_seg, &status);
-
- cursor_on();
- printf("\nAll Done!\n");
-
- exit(0);
- }
-
- /*1*********************************************************
- * Function: start_timer
- *
- * Summary: Create and start a timer.
- *
- * Invocation: timer_sem = start_timer(timeout);
- *
- * Inputs: timeout (unsigned int) - timer interval
- * in seconds
- *
- * Outputs: timer_sem (selector) - the semaphore that will
- * receive a unit at each timer interval
- *
- * Caveats: Accesses the time/date data segment that is
- * shared with the clock_task().
- ***********************************************************/
-
- selector start_timer(unsigned int timeout)
- {
- unsigned int status;
- unsigned int indx;
- unsigned int done;
- unsigned int no_more_timers;
-
- selector timer_sem;
- selector current_job;
- selector clock_sem;
- selector sys_time_seg;
-
- struct SYS_TIME_STR *sys_time;
-
- indx = 0;
- done = FALSE;
- no_more_timers = TRUE;
- timer_sem = NUL_TKN;
-
- /* Get objects for access semaphore and */
- /* time/date data segment */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- clock_sem = rqlookupobject(current_job,
- &clock_sem_name, NO_WAIT, &status);
- sys_time_seg = rqlookupobject(current_job,
- &time_seg_name, NO_WAIT, &status);
-
- sys_time = buildptr(sys_time_seg, 0);
-
- /* Access time/date memory */
-
- rqreceiveunits(clock_sem, 1, WAIT_FOREVER, &status);
-
- /* Find an empty timer slot */
-
- while (!done)
- {
- if (!sys_time->timer[indx].in_use)
- {
- done = TRUE;
- no_more_timers = FALSE;
- }
- else
- {
- indx++;
-
- if (indx == MAX_TIMERS)
- {
- done = TRUE;
- }
- }
- }
-
- /* Establish a timer */
-
- if (no_more_timers == FALSE)
- {
- if (timeout != 0)
- {
- timer_sem = rqcreatesemaphore(SEM_INIT_0,
- 999, FIFO_SEM, &status);
- sys_time->timer[indx].in_use = TRUE;
- sys_time->timer[indx].count = 0;
- sys_time->timer[indx].timeout = timeout;
- sys_time->timer[indx].sem_tkn = timer_sem;
- }
- }
-
- /* Release time/date memory */
-
- rqsendunits(clock_sem, 1, &status);
-
- /* Return timer semaphore to caller */
-
- return(timer_sem);
- }
-
- /*1*********************************************************
- * Function: stop_timer
- *
- * Summary: Delete a timer.
- *
- * Invocation: timer_sem = start_timer(timeout);
- *
- * Inputs: timeout (unsigned int) - timer interval
- * in seconds
- *
- * Outputs: timer_sem (selector) - the semaphore that will
- * receive a unit at each timer interval
- *
- * Caveats: Accesses the time/date data segment that is
- * shared with the clock_task().
- ***********************************************************/
-
- unsigned int stop_timer(selector timer_sem)
- {
- unsigned int status;
- unsigned int indx;
- unsigned int done;
- unsigned int invalid_timer;
-
- selector current_job;
- selector clock_sem;
- selector sys_time_seg;
-
- struct SYS_TIME_STR *sys_time;
-
-
- indx = 0;
- done = FALSE;
- invalid_timer = TRUE;
-
- /* Get objects for access semaphore and */
- /* time/date data segment */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- clock_sem = rqlookupobject(current_job,
- &clock_sem_name, NO_WAIT, &status);
- sys_time_seg = rqlookupobject(current_job,
- &time_seg_name, NO_WAIT, &status);
-
- sys_time = buildptr(sys_time_seg, 0);
-
- /* Access time/date memory. */
-
- rqreceiveunits(clock_sem, 1, WAIT_FOREVER, &status);
-
- /* Locate and remove this timer */
-
- while (!done)
- {
- if (sys_time->timer[indx].in_use &&
- (sys_time->timer[indx].sem_tkn == timer_sem))
- {
- rqdeletesemaphore(timer_sem, &status);
- sys_time->timer[indx].in_use = FALSE;
- sys_time->timer[indx].sem_tkn = NUL_TKN;
- sys_time->timer[indx].count = 0;
- sys_time->timer[indx].timeout = 0;
- done = TRUE;
- invalid_timer = FALSE;
- }
- else
- {
- indx++;
-
- if (indx == MAX_TIMERS)
- {
- done = TRUE;
- }
- }
- }
-
- /* Release time/date memory */
-
- rqsendunits(clock_sem, 1, &status);
-
- /* Return with result of call */
-
- return (invalid_timer ? ERROR : EOK);
- }
-
-
- /*1*********************************************************
- * Task: count_task
- *
- * Summary: Continuously counts and displays a value from
- * 0-65535.
- *
- * Caveats: Communicates with the crt_task() for displaying
- * counter values.
- ***********************************************************/
-
- void count_task(void)
- {
- unsigned char counter_buf[6];
-
- selector current_job;
- selector rsp_mbx;
- selector crt_req_mbx;
- selector init_sem;
- selector count_shtdwn_sem;
- selector req_seg;
-
- unsigned int counter;
- unsigned int status;
-
- struct CRT_REQ_STR *req_msg;
-
- struct EXCEPTIONSTRUCT exceptioninfo;
-
- /* Disable this task's exception handler */
-
- rqgetexceptionhandler(&exceptioninfo, &status);
- exceptioninfo.exceptionmode = 0;
- rqsetexceptionhandler(&exceptioninfo, &status);
-
- /* Lookup/Create needed objects */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- init_sem = rqlookupobject(current_job,
- &init_sem_name, NO_WAIT, &status);
-
- count_shtdwn_sem = rqlookupobject(current_job,
- &count_shtdwn_sem_name, NO_WAIT, &status);
-
- rsp_mbx = rqcreatemailbox(FIFO_OBJ_MBX, &status);
-
- crt_req_mbx = rqlookupobject(current_job,
- &crt_req_mbx_name, NO_WAIT, &status);
-
- /* Initialize request message */
-
- req_seg = rqcreatesegment(
- sizeof(struct CRT_REQ_STR), &status);
-
- req_msg = buildptr(req_seg, 0);
-
- req_msg->msg_ptr = counter_buf;
- req_msg->row = 12;
- req_msg->col = 38;
-
- /* Singal that initialization is completed. */
-
- rqsendunits(init_sem, 1, &status);
-
- /* Continuously count 0-65535 and display the */
- /* value until signalled to stop. */
-
- counter = 0;
-
- rqreceiveunits(count_shtdwn_sem, 1, NO_WAIT, &status);
-
- while (status == ETIME) /* while no signal received */
- {
- sprintf(counter_buf, "%d", counter);
- rqsendmessage(crt_req_mbx,
- req_seg, rsp_mbx, &status);
- req_seg = rqreceivemessage(rsp_mbx,
- WAIT_FOREVER, NUL_TKN, &status);
- counter++;
- rqreceiveunits(count_shtdwn_sem, 1, NO_WAIT, &status);
- }
-
- /* Cleanup objects created by this task. */
-
- rqdeletemailbox(rsp_mbx, &status);
- rqdeletesegment(req_seg, &status);
-
- /* Signal shutdown complete and suspend execution. */
-
- rqsendunits(init_sem, 1, &status);
-
- rqsuspendtask(NUL_TKN, &status); /* suspend this task */
- }
-
- /*1*********************************************************
- * Task: timer_task
- *
- * Summary:
- *
- * Caveats:
- ***********************************************************/
-
- void timer_task(void)
- {
- selector current_job;
- selector init_sem;
- selector clock_sem;
- selector timer_sem;
-
- unsigned int status;
-
- struct EXCEPTIONSTRUCT exceptioninfo;
-
- /* Disable this task's exception handler */
-
- rqgetexceptionhandler(&exceptioninfo, &status);
- exceptioninfo.exceptionmode = 0;
- rqsetexceptionhandler(&exceptioninfo, &status);
-
- /* Lookup needed objects */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- init_sem = rqlookupobject(current_job,
- &init_sem_name, NO_WAIT, &status);
-
- /* Start a one-second timer. If the timer was */
- /* created, wait for 20 seconds (units) then stop */
- /* stop the timer. */
-
- timer_sem = start_timer(1);
-
- if (timer_sem != NUL_TKN)
- {
- rqreceiveunits(timer_sem, 20, WAIT_FOREVER, &status);
- stop_timer(timer_sem);
- }
-
- /* Signal task finished and suspend execution. */
-
- rqsendunits(init_sem, 1, &status);
-
- rqsuspendtask(NUL_TKN, &status); /* suspend this task */
- }
-
- /*1*********************************************************
- * Functions: clrscrn, cursor_on, cursor_off, print_at
- *
- * Summary: Functions for basic display control.
- *
- * Invocation: clrscrn();
- * curson_on();
- * cursoff_on();
- *
- * Invocation: print_at(row, col, msg_ptr)
- *
- * Inputs: row (unsigned int) - row position
- * col (unsigned int) - column position
- * msg_ptr (unsigned char *) - message string pointer
- *
- * Caveats: Escape sequences are for a WYSE60 terminal.
- ***********************************************************/
-
- void clrscrn(void)
- {
- fprintf(stdout, "\x1B+");
- fflush(stdout);
- return;
- }
-
- void cursor_on(void)
- {
- fprintf(stdout, "\x1B`1");
- fflush(stdout);
- return;
- }
-
- void cursor_off(void)
- {
- fprintf(stdout, "\x1B`0");
- fflush(stdout);
- return;
- }
-
- void print_at(unsigned int row,
- unsigned int col, unsigned char *msg_ptr)
- {
- fprintf(stdout, "\x1B=%c%c%s",
- (row + 31), (col + 31), msg_ptr);
- fflush(stdout);
- return;
- }
-
- /*1*********************************************************
- * Task: crt_task
- *
- * Summary:
- *
- * Caveats:
- ***********************************************************/
-
- void crt_task(void)
- {
- selector current_job;
- selector req_mbx;
- selector rsp_mbx;
- selector req_seg;
- selector init_sem;
- selector crt_shtdwn_sem;
-
- unsigned int status;
-
- struct CRT_REQ_STR *req_msg;
-
- struct EXCEPTIONSTRUCT exceptioninfo;
-
- /* Disable this task's exception handler */
-
- rqgetexceptionhandler(&exceptioninfo, &status);
- exceptioninfo.exceptionmode = 0;
- rqsetexceptionhandler(&exceptioninfo, &status);
-
- /* Lookup/Create needed objects */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- init_sem = rqlookupobject(current_job,
- &init_sem_name, WAIT_FOREVER, &status);
-
- crt_shtdwn_sem = rqlookupobject(current_job,
- &crt_shtdwn_sem_name, WAIT_FOREVER, &status);
-
- req_mbx = rqcreatemailbox(FIFO_OBJ_MBX, &status);
- rqcatalogobject(current_job,
- req_mbx, &crt_req_mbx_name, &status);
-
- /* Initialize display */
-
- cursor_off();
- clrscrn();
-
- /* Signal initialization complete */
-
- rqsendunits(init_sem, 1, &status);
-
-
- rqreceiveunits(crt_shtdwn_sem, 1, NO_WAIT, &status);
-
- while (status == ETIME)
- {
- req_seg = rqreceivemessage(req_mbx,
- WAIT_FOREVER, &rsp_mbx, &status);
-
- req_msg = buildptr(req_seg, 0);
-
- print_at(req_msg->row,
- req_msg->col, req_msg->msg_ptr);
-
- if (rsp_mbx != NUL_TKN)
- {
- rqsendmessage(rsp_mbx, req_seg, NUL_TKN, &status);
- }
- else
- {
- rqdeletesegment(req_seg, &status);
- }
-
- rqreceiveunits(crt_shtdwn_sem, 1, NO_WAIT, &status);
- }
-
- rqsendunits(init_sem, 1, &status);
-
- for(;;)
- {
- req_seg = rqreceivemessage(req_mbx,
- WAIT_FOREVER, &rsp_mbx, &status);
-
- if (rsp_mbx != NUL_TKN)
- {
- rqsendmessage(rsp_mbx, req_seg, NUL_TKN, &status);
- }
- else
- {
- rqdeletesegment(req_seg, &status);
- }
- }
- }
-
- /*1*********************************************************
- * Function: read_time
- *
- * Summary: Read a specified time/date register of the
- * hardware clock.
- *
- * Invocation: in_byte = read_time(reg);
- *
- * Inputs: reg (unsigned char) - the hardware time/date
- * register to be read
- *
- * Outputs: in_byte (unsigned char) - the value of the
- * register read
- *
- * Caveats: None
- ***********************************************************/
-
- unsigned char read_time(unsigned char reg)
- {
- unsigned char in_byte;
-
- outbyte(CNT_PORT, HOLD_HIGH);
- delay(3);
- outbyte(CNT_PORT, HOLD_READ);
- delay(1);
- outbyte(ADR_PORT, reg);
- delay(1);
- in_byte = inbyte(DAT_PORT);
- outbyte(CNT_PORT, CNT_RST);
- delay(1);
-
- return (in_byte);
- }
-
- /*1*********************************************************
- * Function: write_time
- *
- * Summary: Write a byte to the specified time/date register
- * of the hardware clock.
- *
- * Invocation: write_time(reg, out_byte);
- *
- * Inputs: reg (unsigned char) - the hardware time/date
- * register
- *
- * out_byte (unsigned char) - the value to be
- * written to the hardware clock register
- *
- * Caveats: None
- ***********************************************************/
-
- void write_time(unsigned char reg, unsigned char out_byte)
- {
- outbyte(CNT_PORT, HOLD_HIGH);
- delay(3);
- outbyte(ADR_PORT, reg);
- delay(1);
- outbyte(DAT_PORT, out_byte);
- delay(1);
- outbyte(CNT_PORT, HOLD_WRITE);
- delay(1);
- outbyte(CNT_PORT, CNT_RST);
- delay(1);
-
- return;
- }
-
- /*1*********************************************************
- * Function: read_clock
- *
- * Summary: Read the time/date from the hardware clock and
- * stores it in the global time/date structure.
- *
- * Invocation: read_clock();
- *
- * Caveats: Requires the caller to obtain access the shared
- * time/date data segment.
- ***********************************************************/
-
- void read_clock(void)
- {
- unsigned char time_buf[13];
- unsigned int i;
-
- /* Set mode */
-
- outbyte(PIO_PORT, PIO_READ);
- delay(1);
-
- /* Set control lines to disable interrupts */
-
- outbyte(CNT_PORT, CNT_RST);
- delay(1);
-
- /* Read time/date */
-
- for (i = 0 ; (i <= 12); i++)
- {
- time_buf[i] = read_time(i);
- }
-
- sys_time->second =
- (10 * (time_buf[SEC10_REG] & 0x07)) +
- (time_buf[SEC01_REG] & 0x0F);
- sys_time->minute =
- (10 * (time_buf[MIN10_REG] & 0x07)) +
- (time_buf[MIN01_REG] & 0x0F);
- sys_time->hour =
- (10 * (time_buf[HRS10_REG] & 0x03)) +
- (time_buf[HRS01_REG] & 0x0F);
- sys_time->date =
- (10 * (time_buf[DAT10_REG] & 0x03)) +
- (time_buf[DAT01_REG] & 0x0F);
- sys_time->month =
- (10 * (time_buf[MON10_REG] & 0x01)) +
- (time_buf[MON01_REG] & 0x0F);
- sys_time->year =
- (10 * (time_buf[YRS10_REG] & 0x0F)) +
- (time_buf[YRS01_REG] & 0x0F);
-
- /* Reset control lines to enable interrupts */
-
- outbyte(CNT_PORT, INT_ENB);
- delay(1);
-
- outbyte(ADR_PORT, 0x0F);
- delay(1);
-
- return;
- }
-
- /*1*********************************************************
- * Function: write_clock
- *
- * Summary: Uses the global time/date structure to write a
- * new time/date to the hardware clock.
- *
- * Invocation: write_clock();
- *
- * Caveats: Requires the caller to obtain access the shared
- * time/date data segment.
- ***********************************************************/
-
- void write_clock(void)
- {
- unsigned char temp_byte;
-
- /* Set mode */
-
- outbyte(PIO_PORT, PIO_WRITE);
- delay(1);
-
- /* Set control lines to disable interrupts */
-
- outbyte(CNT_PORT, CNT_RST);
- delay(1);
-
- /* Write time/date. Seconds always set to 0 */
-
- sys_time->second = 0;
- write_time(SEC01_REG, 0);
- write_time(SEC10_REG, 0);
-
- temp_byte =
- sys_time->minute - (10 * (sys_time->minute / 10));
- write_time(MIN01_REG, temp_byte);
- temp_byte = sys_time->minute / 10;
- write_time(MIN10_REG, temp_byte);
-
- temp_byte =
- sys_time->hour - (10 * (sys_time->hour / 10));
- write_time(HRS01_REG, temp_byte);
- temp_byte =
- (sys_time->hour / 10) | 0x08; /* 24hr format */
- write_time(HRS10_REG, temp_byte);
-
- temp_byte =
- sys_time->date - (10 * (sys_time->date / 10));
- write_time(DAT01_REG, temp_byte);
- temp_byte = sys_time->date / 10;
- write_time(DAT10_REG, temp_byte);
-
- temp_byte =
- sys_time->month - (10 * (sys_time->month / 10));
- write_time(MON01_REG, temp_byte);
- temp_byte = sys_time->month / 10;
- write_time(MON10_REG, temp_byte);
-
- temp_byte =
- sys_time->year - (10 * (sys_time->year / 10));
- write_time(YRS01_REG, temp_byte);
- temp_byte = sys_time->year / 10;
- write_time(YRS10_REG, temp_byte);
-
- /* Reset mode */
-
- outbyte(PIO_PORT, PIO_READ);
- delay(1);
-
- /* Reset control lines to enable interrupts */
-
- outbyte(CNT_PORT, INT_ENB);
- delay(1);
-
- outbyte(ADR_PORT, 0x0F);
- delay(1);
-
- return;
- }
-
- /*1*********************************************************
- * Function: reset_timers
- *
- * Summary: Initializes (zero out) all timer slots of the
- * shared time/date data segment.
- *
- * Invocation: reset_timers();
- *
- * Caveats: Requires the caller to obtain access the shared
- * time/date data segment.
- ***********************************************************/
-
- void reset_timers(void)
- {
- unsigned int i;
-
- for (i = 0 ; i < MAX_TIMERS; i++)
- {
- sys_time->timer[i].in_use = FALSE;
- sys_time->timer[i].sem_tkn = NUL_TKN;
- sys_time->timer[i].count = 0;
- sys_time->timer[i].timeout = 0;
- }
-
- return;
- }
-
- /*1*********************************************************
- * Function: advance_timers
- *
- * Summary: Increments all active timers in the shared
- * time/date data segment by one second.
- *
- * Invocation: advance_timers();
- *
- * Caveats: Requires the caller to obtain access the shared
- * time/date data segment.
- ***********************************************************/
-
- void advance_timers(void)
- {
- unsigned int i;
- unsigned int status;
-
-
- for (i = 0 ; i < MAX_TIMERS; i++)
- {
- if (sys_time->timer[i].in_use)
- {
- sys_time->timer[i].count++;
-
- if (sys_time->timer[i].count >=
- sys_time->timer[i].timeout)
- {
- rqsendunits(
- sys_time->timer[i].sem_tkn, 1, &status);
- sys_time->timer[i].count = 0;
- }
- }
- }
-
- return;
- }
-
- /*1*********************************************************
- * Function: advance_time_date
- *
- * Summary: Increments the time/date (hh:mm:ss mm/dd/yy) in
- * the shared time/date data segment by one second.
- *
- * Invocation: advance_time_date();
- *
- * Caveats: Requires the caller to obtain access the shared
- * time/date data segment.
- ***********************************************************/
-
- void advance_time_date(void)
- {
- if (sys_time->second < 59)
- {
- sys_time->second++;
- }
- else
- {
- sys_time->second = 0;
-
- if (sys_time->minute < 59)
- {
- sys_time->minute++;
- }
- else
- {
- sys_time->minute = 0;
-
- if (sys_time->hour < 23)
- {
- sys_time->hour++;
- }
- else
- {
- sys_time->hour = 0;
-
- if (sys_time->date <
- days_in_month[sys_time->month - 1])
- {
- sys_time->date++;
- }
- else
- {
- if (sys_time->month == FEBRUARY)
- {
- /* Check for leap year (only good through 2100) */
-
- if (((sys_time->year % 4) == 0) &&
- (sys_time->date == 28))
- {
- sys_time->date = 29;
- }
- else
- {
- sys_time->month = MARCH;
- sys_time->date = 1;
- }
- }
- else
- {
- sys_time->date = 1;
-
- if (sys_time->month < DECEMBER)
- {
- sys_time->month++;
- }
- else
- {
- sys_time->month = JANUARY;
-
- if (sys_time->year < 99)
- {
- sys_time->year++;
- }
- else
- {
- sys_time->year = 0;
- }
- }
- }
- }
- }
- }
- }
-
- return;
- }
-
- /*1*********************************************************
- * Function: start_timer
- *
- * Summary: Create and start a timer.
- *
- * Invocation: timer_sem = start_timer(timeout);
- *
- * Inputs: timeout (unsigned int) - timer interval
- * in seconds
- *
- * Outputs: timer_sem (selector) - the semaphore that will
- * receive a unit at each timer interval
- *
- * Caveats: The interrupt handler will signal the
- * interrupt task to finish servicing the
- * interrupt.
- ***********************************************************/
-
- /* Tell the compiler that this function is an interrupt */
- /* routine so it can generate proper code for entering */
- /* and exiting the interrupt routine. */
-
- #pragma interrupt("clockint_handler")
-
- void clockint_handler(void)
- {
- unsigned int status;
-
- /* Signal the interrupt task */
-
- rqsignalinterrupt(CLOCK_INT_LEVEL, &status);
-
- return;
- }
-
- /*1*********************************************************
- * Task: clock_task
- *
- * Summary: Services interrupts from the hardware clock.
- * Also maintains/updates the global time/date
- * data and services software timers.
- *
- * Caveats: Communicates with the crt_task() to display the
- * current time/date.
- ***********************************************************/
-
- void clock_task(void)
- {
- char time_string[19];
-
- unsigned int status;
- unsigned int retry;
-
- selector current_job;
- selector init_sem;
- selector clock_sem;
- selector clock_shtdwn_sem;
- selector rsp_seg;
- selector req_seg;
- selector crt_req_mbx;
- selector rsp_mbx;
-
- struct CRT_REQ_STR *req_msg;
-
- struct EXCEPTIONSTRUCT exceptioninfo;
-
- /* Disable this task's exception handler */
-
- rqgetexceptionhandler(&exceptioninfo, &status);
- exceptioninfo.exceptionmode = 0;
- rqsetexceptionhandler(&exceptioninfo, &status);
-
- /* Disable any current interrupt task */
-
- rqresetinterrupt(CLOCK_INT_LEVEL, &status);
-
- /* Lookup/Create needed objects */
-
- current_job = rqgettasktokens(THIS_JOB, &status);
-
- init_sem = rqlookupobject(current_job,
- &init_sem_name, NO_WAIT, &status);
-
- clock_sem = rqlookupobject(current_job,
- &clock_sem_name, NO_WAIT, &status);
-
- sys_time_seg = rqlookupobject(current_job,
- &time_seg_name, NO_WAIT, &status);
-
- clock_shtdwn_sem = rqlookupobject(current_job,
- &clock_shtdwn_sem_name, NO_WAIT, &status);
-
- crt_req_mbx = rqlookupobject(current_job,
- &crt_req_mbx_name, NO_WAIT, &status);
-
- sys_time = buildptr(sys_time_seg, 0);
-
- rsp_mbx = rqcreatemailbox(FIFO_OBJ_MBX, &status);
-
- /* Initialize time string buffer */
-
- memset(&time_string, ' ', sizeof(time_string));
-
- /* Initialize crt_task() request message and */
- /* send it to the response mailbox to setup */
- /* for the processing loop. */
-
- req_seg = rqcreatesegment(
- sizeof(struct CRT_REQ_STR), &status);
- req_msg = buildptr(req_seg, 0);
-
- req_msg->msg_ptr = &time_string;
- req_msg->row = 1;
- req_msg->col = 60;
-
- rqsendmessage(rsp_mbx, req_seg, NUL_TKN, &status);
-
- /* Initialize retry counter and timers */
-
- retry = 0;
- sys_time->change_flg = FALSE;
- reset_timers();
-
- /* Initialize and read hardware clock */
-
- outbyte(PIO_PORT, PIO_READ);
- delay(1);
-
- outbyte(CNT_PORT, INT_ENB);
- delay(1);
-
- outbyte(ADR_PORT, 0x0F);
- delay(1);
-
- read_clock();
-
- /* Allow access to time/date memory */
-
- rqsendunits(clock_sem, 1, &status);
-
- /* Set interrupt vector */
-
- rqsetinterrupt(CLOCK_INT_LEVEL, 1,
- &clockint_handler, NUL_TKN, &status);
-
- /* Signal initialization complete */
-
- rqsendunits(init_sem, 1, &status);
-
- /* Process interrupt signals until shutdown */
-
- rqreceiveunits(clock_shtdwn_sem, 1, NO_WAIT, &status);
-
- while (status == ETIME) /* while no signal received */
- {
- /* Wait no longer than 2 seconds for interrupt signal */
-
- rqetimedinterrupt(CLOCK_INT_LEVEL, 200, &status);
-
- /* If an interrupt is NOT received, attempt to reset */
- /* the hardware clock. */
-
- if (status == ETIME) /* if no interrupt */
- {
- retry++;
-
- /* Once the maximum number of retries is reached, */
- /* give up. Retrieve outstanding display request */
- /* and wait for shutdown. When shutdown signal is */
- /* received, disable this interrupt task, signal */
- /* shutdown complete and suspend execution. */
-
- if (retry == MAX_CLOCK_RETRIES)
- {
- req_seg = rqreceivemessage(rsp_mbx,
- WAIT_FOREVER, NUL_TKN, &status);
- rqreceiveunits(clock_shtdwn_sem, 1,
- WAIT_FOREVER, &status);
- rqresetinterrupt(CLOCK_INT_LEVEL, &status);
- rqsendunits(init_sem, 1, &status);
- rqsuspendtask(NUL_TKN, &status);
- }
-
- /* Reinitialize hardware clock */
-
- outbyte(PIO_PORT, PIO_READ);
- delay(1);
-
- outbyte(CNT_PORT, INT_ENB);
- delay(1);
-
- outbyte(ADR_PORT, 0x0F);
- delay(1);
-
- /* Re-read hardware clock */
-
- rqreceiveunits(clock_sem, 1,
- WAIT_FOREVER, &status);
-
- read_clock();
-
- rqsendunits(clock_sem, 1, &status);
- }
- else
- {
- /* Interrupt signal received, reset retry count */
-
- retry = 0;
-
- /* Access time/date memory */
-
- rqreceiveunits(clock_sem, 1,
- WAIT_FOREVER, &status);
-
- /* If needed, update hardware clock with new */
- /* time/date data. Otherwise, advance the */
- /* time/data data by one second. */
-
- if (sys_time->change_flg)
- {
- write_clock();
- sys_time->change_flg = 0;
- }
- else
- {
- advance_time_date();
- }
-
- /* Advance any timers by one second */
-
- advance_timers();
-
- /* Prepare time/date data for display */
-
- sprintf(time_string, "%02d:%02d:%02d %02d/%02d/%02d",
- sys_time->hour, sys_time->minute, sys_time->second,
- sys_time->month, sys_time->date, sys_time->year);
-
- /* Release time/date memory */
-
- rqsendunits(clock_sem, 1, &status);
-
- /* If previous display request has finished(segment */
- /* returned), then request new time/date be displayed */
-
- rsp_seg = rqreceivemessage(rsp_mbx,
- NO_WAIT, NUL_TKN, &status);
-
- if (status != ETIME)
- {
- rqsendmessage(crt_req_mbx,
- req_seg, rsp_mbx, &status);
- }
- }
-
- /* Check for shutdown */
-
- rqreceiveunits(clock_shtdwn_sem, 1, NO_WAIT, &status);
- }
-
- /* Retrieve outstanding display request, disable */
- /* this interrupt task, signal shutdown complete */
- /* and suspend execution. */
-
- req_seg = rqreceivemessage(rsp_mbx,
- WAIT_FOREVER, NUL_TKN, &status);
-
- rqsendunits(init_sem, 1, &status);
-
- rqresetinterrupt(CLOCK_INT_LEVEL, &status);
-
- rqsuspendtask(NUL_TKN, &status); /* suspend this task */
- }
-